
import json
import socket
import sys
import time
import muliticast_accepter 

from util.util_net import NetUtil
from util.util_system import SystemUtil

from util.log_util import getLogger
from device_util import DeviceUtil, DeviceInfo

logger = getLogger()

class Server:
    def __init__(self, multicast_group = "239.1.1.100", port = 5555):
        self.multicast_group = multicast_group
        self.port = port
        local_interface = DeviceUtil.load_config().ip
        self.accepter = muliticast_accepter.MulticastReceiver(self.multicast_group, self.port, self.__on_data_received, local_interface)

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if hasattr(self.accepter, 'stop'):
            self.accepter.stop()
        if exc_type is not None:
            logger.error(f"服务运行异常: {exc_val}")
        return False

    def start(self):
        self.accepter.start()

    def stop(self):
        self.accepter.stop()

    def __on_data_received(self, data : bytes, addr):
        try:
            res_text = data.decode("utf-8", errors="ignore")
            req_json = json.loads(res_text)
            logger.debug(f"收到请求: {req_json}, 地址: {addr}")

            if not isinstance(req_json, dict) or "type" not in req_json:
                logger.warning(f"无效的请求格式: {req_json}")
                return

            if (req_json["type"] == "response"):
                return
            if (req_json["type"] == "request"):
                # logger.debug(f"收到请求: {req_json}")
                if "url" not in req_json or "data" not in req_json:
                    logger.warning(f"请求缺少必要字段: {req_json}")
                    return

                if (req_json["url"] == "/device/search"):
                    self.__on_handle_device_search(req_json["data"])
                elif (req_json["url"] == "/device/modify"):
                    self.__on_handle_device_modify(req_json["data"])
                elif (req_json["url"] == "/device/time/set"):
                    self.__on_handle_device_time_set(req_json["data"])
                elif (req_json["url"] == "/device/time/get"):
                    self.__on_handle_device_time_get(req_json["data"])
                else:
                    logger.warning(f"未知请求: {req_json}")
        except json.JSONDecodeError as e:
            logger.error(f"JSON解析失败: {e}, 原始数据: {data}")
        except Exception as e:
            logger.error(f"处理请求时发生异常: {e}")

    def __on_handle_device_search(self, data):
        try:
            logger.info(f"收到设备发现请求: {data}")
            if "client_id" not in data:
                logger.warning(f"设备发现请求缺少 client_id: {data}")
                return

            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
                sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64)
                device = DeviceUtil.load_config()

                response = {
                    "type": "response",
                    "url": "/device/search",
                    "client_id": data["client_id"],
                    "data": {
                        "name": device.name,
                        "serial": device.serial,
                        "remark": device.remark,
                        "ip": device.ip,
                        "submask": device.submask,
                        "gateway": device.gateway,
                        "ntp_url": device.ntp_url,
                    }
                }
                response_json = json.dumps(response)
                sock.sendto(response_json.encode("utf-8"), (self.multicast_group, self.port))
        except Exception as e:
            logger.error(f"处理设备发现请求时发生异常: {e}")

    def __on_handle_device_modify(self, data):
        try:
            logger.info(f"收到设备修改请求: {data}")
            required_fields = ["serial", "name", "ip", "submask", "gateway", "client_id"]
            for field in required_fields:
                if field not in data:
                    logger.warning(f"设备修改请求缺少必要字段 {field}: {data}")
                    return

            device = DeviceUtil.load_config()
            if data["serial"] != device.serial:
                logger.error(f"序列号不匹配: 请求序列号 {data['serial']}, 设备序列号 {device.serial}")
                return

            device.name = data["name"]
            device.remark = data.get("remark", "")
            device.ip = data["ip"]
            device.submask = data["submask"]
            device.gateway = data["gateway"]
            device.ntp_url = data["ntp_url"]

            ret, msg = DeviceUtil.applyDevice(device)
            if ret:
                ret = DeviceUtil.save_config(device)
                msg = "配置成功" if ret else "保存配置失败"

            time.sleep(10)

            self.accepter = muliticast_accepter.MulticastReceiver(self.multicast_group, self.port, self.__on_data_received, device.ip)
            self.accepter.start()
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
                sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64)

                response = {
                    "type": "response",
                    "url": "/device/modify",
                    "client_id": data["client_id"],
                    "data": {
                        "flag": ret,
                        "message": msg
                    }
                }
                response_json = json.dumps(response)
                sock.sendto(response_json.encode("utf-8"), (self.multicast_group, self.port))
        except Exception as e:
            logger.error(f"处理设备修改请求时发生异常: {e}")

    def __on_handle_device_time_set(self, data):
        try:
            logger.info(f"收到时间同步请求: {data}")
            if "serial" not in data or "client_id" not in data or "timestamp_ms" not in data:
                logger.warning(f"时间同步请求缺少必要字段: {data}")
                return

            device = DeviceUtil.load_config()
            if data["serial"] != device.serial:
                logger.warning(f"序列号不匹配: 请求序列号 {data['serial']}, 设备序列号 {device.serial}")
                return

            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
                sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64)
                ret, msg = SystemUtil.set_system_time(data["timestamp_ms"])
                
                response = {
                    "type": "response",
                    "url": "/device/time/set",
                    "client_id": data["client_id"],
                    "data": {
                        "flag": ret,
                        "message": msg
                    }
                }
                response_json = json.dumps(response)
                sock.sendto(response_json.encode("utf-8"), (self.multicast_group, self.port))
        except Exception as e:
            logger.error(f"处理时间同步请求时发生异常: {e}")

    def __on_handle_device_time_get(self, data):
        try:
            # logger.info(f"收到时间获取请求: {data}")
            if "serial" not in data or "client_id" not in data:
                logger.warning(f"时间获取请求缺少必要字段: {data}")
                return

            device = DeviceUtil.load_config()
            if data["serial"] != device.serial:
                logger.warning(f"序列号不匹配: 请求序列号 {data['serial']}, 设备序列号 {device.serial}")
                return

            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
                sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64)
                response = {
                    "type": "response",
                    "url": "/device/time/get",
                    "client_id": data["client_id"],
                    "data": {
                        "timestamp_ms": SystemUtil.get_current_timestamp_ms()
                    }
                }
                response_json = json.dumps(response)
                sock.sendto(response_json.encode("utf-8"), (self.multicast_group, self.port))
        except Exception as e:
            logger.error(f"处理时间获取请求时发生异常: {e}")

if __name__ == "__main__":
    try:
        # 检查管理员权限
        if not SystemUtil.is_admin():
            logger.warning("当前未以管理员权限运行，尝试提权...")
            if not SystemUtil.run_as_admin():
                logger.error("提权失败，程序退出！")
                sys.exit(-1)

        logger.info("正在启动设备服务...")
        
        # 加载配置
        device = DeviceUtil.load_config()
        if device is None:
            logger.error("加载配置失败，程序退出！")
            sys.exit(-1)

        ret, msg = SystemUtil.sntp_sync_time(device.ntp_url)
        if not ret:
            logger.error(msg)
            # sys.exit(-1)

        logger.info(f"设备启动信息:\n{device}")
        
        # 启动服务
        with Server("239.1.1.100", 5555) as server:
            logger.info("服务已启动，正在监听组播数据...")
            try:
                # 保持主线程运行
                while True:
                    time.sleep(1)
            except KeyboardInterrupt:
                logger.info("\n用户中断，停止接收")
    except Exception as e:
        # input("按回车键退出服务...\n")
        logger.error(f"服务启动失败: {e}")
        sys.exit(-1)
